package md.cm.base;

import lombok.*;
import md.cm.geography.Adminunit;
import md.cm.unit.Unit;
import org.fjsei.yewu.aop.hibernate.AdminunitBinder;
import org.fjsei.yewu.aop.hibernate.FullNameBinder;
import org.fjsei.yewu.aop.hibernate.UnitNameBinder;
import org.fjsei.yewu.filter.Uunode;
import org.fjsei.yewu.util.Tool;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.search.engine.backend.types.Aggregable;
import org.hibernate.search.engine.backend.types.ObjectStructure;
import org.hibernate.search.engine.backend.types.Projectable;
import org.hibernate.search.engine.backend.types.Sortable;
import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.PropertyBinderRef;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.TypeBinderRef;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.*;

import jakarta.persistence.*;
import java.util.UUID;
//不采用接口/微服务/Rest方式，扯皮和费用授权问题多；反正这个大数据类别的事实上的实时一致性要求很低。
//采用本地维护模式，只能自己拷贝数据/一部分我方用到的大数据，面临更新滞后和不一致问题？本地建库表no是外部大数据库关键ID标识，id是我方内部1:1对应ID。
/** 企业和组织表
 * Company实际上可以完全独立出去，有可能单独的库或单独服务或系统来提供该块相应的功能： 搜索、信息。
 * 注意：Unit实体实际是 业务范畴的概念，可能不同平台系统对Unit的需求差异巨大，所以Unit变化特别大，各种XxxUnit模型实体？？。
 *  注意@UniqueConstraint(columnNames={"no"})默认是大小写不区分的，都能算选中。
 *  暂时去掉约束：初期数据重复多；整理维护后，正式运行环境去重新添加约束。@Table(uniqueConstraints={@UniqueConstraint(columnNames={"no"}) })
 * */

@Getter
@Setter
@Entity
//@Table( uniqueConstraints = {@UniqueConstraint(columnNames={"name"})} )
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder=true)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region ="Slow")
@Indexed
//@TypeBinding(binder = @TypeBinderRef(type = FullNameBinder.class))
public class Company implements CompanyPi, Uunode,NamePi {
    //Hibernate Search正常的ID无需要加@DocumentID标注的。
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    /** UNT_NAME ：也是单位唯一性字段！
     * 使用单位 USE_UNT_NAME,
     * 对于已经存在于数据库当中的 重名 数据，本平台启动后并不会报警的。需要手动维护数据；除非新增加才会报错
     * 【实际上问题】 企业消完后，其名称可能内后来者重新启用，但是no可就不一样了；企业no终身不变性质。
     * */
    @FullTextField
    @Column(unique = true,length = 150)
    private String name;    //UNT_NAME

    /**社会信用代码：UNT_ORG_COD , USE_UNT_ORGCOD,
     *  不可重复！【管理问题=会重复！】
     * 统一社会信用代码用18位阿拉伯数字或大写英文字母表示?
     * 统一代码及其9位主体标识码（组织机构代码）在全国范围内是唯一的。
     统一社会信用代码分为两类：一类是识别自然人的代码，就是公民身份证号码；另一类是识别单位的代码，就是法人和其他组织统一社会信用代码，编码长度和个人身份证号码一样。
     找不到用代码判定的肯定无错误办法：全国统一社会信用代码规则&身份证号码规则，个人公司还是需要输入原始端就要区分开！！
     * */
    @KeywordField(sortable = Sortable.YES)
    private String no;   //统一社会信用代码

    /**外部来源
     * 注册登记的地址：UNT_ADDR  ,USE_UNT_ADDR;
     * 和pos的定位不一定完全一样。初始化两个一样的地址；
     * 配合Adminunit把ES上相应本字段改造为包含了区域名的全文本地址，国内应用：中国两个字前缀省略掉。
     * */
    @FullTextField
    @Column(length = 150)
    private String address;   //不用于搜索CompanyES；

    /**配合地址的 区域代码, 归属登记地 */
//    @IndexedEmbedded
    //@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)   不管对方更新
    @PropertyBinding(binder = @PropertyBinderRef(type = AdminunitBinder.class))
    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn(name = "aid")     //去掉nullable=false，会导致初始化表缺省aid=0
    private Adminunit ad;       //行政区划; 有些同步来源就没指出地区代码。同步生成的需要后期人工合并地址！。

    //var gps = [119.26287, 26.048844];前面的经 后面的纬
    private Double lat;  //纬度 ;精确到小数点后6位可达约1米精度。 ？综合考虑地址所有关联多个设备原始数据，同步时期还未人工确认以最新数据为准。
    private Double lon;  //经度  前面的是纬度,后面的是经度； 其它同步来源不一定有Geo: tb_unt_mge  jc_unt_mge有。

    /**体现行政区划的： 后端比较统计操作容易。 address
    [更新变化快的] 当前实际上的地址，最新办公地址。*/
 //   @ManyToOne(fetch= FetchType.LAZY)
 //   private Address pos;    //多对1，；地理定位 方式。
    /**扩展地址文本串[门牌号] 更能精确定位快递地址
     *目前办公地址： 配合pos扩充详细。
     * */
   // private String  extadr;

    //负责人，　实际上可以定义成Person对象的。　定义成String只是人名字或描述符代号；
    /**使用单位联系人：UNT_LKMEN; 一般是负责人吧;
     * 不同的事情 还会有不同的联系人啊? 特种设备有关的联系人:
     * */
    //@KeywordField(projectable = Projectable.YES)    对搜索来讲就真没意义? 去掉;
    private String linkMen;     //对外 负责人　UNT_LKMEN

    /**使用单位 手机：UNT_MOBILE,
     * 唯一个号码， 需要手机号码：可发送短信的。
     * */
    //@KeywordField(projectable = Projectable.YES)   还是舍弃吧！
    private String phone;

    /**企业单位的 更多联系电话，可任意输入的多个电话号码；
     * 值班总机，固定电话，传真，甚至更多备注。[A/B]
     * */
    private String  tel;


    //若需要双向的1 ：1关系，关系是Unit类维护； 就把下面俩个行添加上。 太多了？很多的业务很多模块插入关联关系字段？
    /**本来不用这个字段的， 因为Hibernate Search自动更新而添加
     * 不能定义上@OneToOne(mappedBy = "company" ,fetch= FetchType.LAZY) 反而会生成更多冗长的语句了。
     * 若没提供本关联字段，HS报错:
     'md.specialEqp.type.Vessel': path '.useu<no value extractors>.company<no value extractors>.name<no value extractors>':
     Unable to find the inverse side of the association on type 'md.cm.unit.Unit' at path '.company<no value extractors>'. Hibernate Search needs this information in order to reindex 'md.cm.unit.Unit'
     when 'md.cm.base.Company' is modified. You can solve this error by defining the inverse side of this association,  either with annotations specific to your integration (@OneToMany(mappedBy = ...) in Hibernate ORM)
     or with the Hibernate Search @AssociationInverseSide annotation. Alternatively, if you do not need to reindex 'md.cm.unit.Unit' when 'md.cm.base.Company' is modified,
     you can disable automatic reindexing with @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
     * */
    @OneToOne(mappedBy = "company")
    private Unit unit;


/*    public void copyAs(UntMge untMge){
        //依照老旧平台来比较修改。
        if(no==null || !no.equals(untMge.getUNT_ORG_COD()) )               no=untMge.getUNT_ORG_COD();
        if(linkMen==null || !linkMen.equals(untMge.getUNT_LKMEN()) )       linkMen=untMge.getUNT_LKMEN();
        if(phone==null || !phone.equals(untMge.getUNT_MOBILE()) )       phone=untMge.getUNT_MOBILE();
        if(origadr ==null || !origadr.equals(untMge.getUNT_ADDR()) )     origadr =untMge.getUNT_ADDR();
    };*/

    @Transient
    public String address(){
        if(null!=ad)
            return(ad.getPrefix()+" "+address);
        else
            return address;
    }
}


//统一社会信用代码是指对中华人民共和国境内每个依法成立和依法注册的单位由各级质量技术监督部门颁发的一个在全国范围内唯一的、始终不变的代码标识,其作用相当于单位的身份证。

